﻿using System;
using System.IO;
using GeneralDFS.BusinessLogical.Nodes;
using GeneralDFS.Common;
using GeneralDFS.DataEntity.IO;
using ProtoBuf;

namespace GeneralDFS.BusinessLogical.FileSystemLogical
{
     [Serializable]
    public class FsImage
    {
        private DirectoryNodeInfo rootDir;
        private NameNode nameNode;
        private String currentDirectory;
        private String dataDirectory;
        private String backDataDirectory;
        private String currentDataFilePath;

        public FsImage(NameNode nameNode)
        {
            this.nameNode = nameNode;
            rootDir = nameNode.Root;
            InitDirectory();
        }

        /// <summary>
        /// 初始化目录，设置当前文件目录地址
        /// </summary>
        public void InitDirectory()
        {
            currentDirectory = Path.Combine(System.Environment.CurrentDirectory,nameNode.GetNodeConfig().ServerName);
            dataDirectory += currentDirectory + "/Data";
            backDataDirectory += dataDirectory + "/BackupData";
            currentDataFilePath += dataDirectory + "/fsImage";

            if (!System.IO.Directory.Exists(dataDirectory))
                System.IO.Directory.CreateDirectory(dataDirectory);

            if (!System.IO.Directory.Exists(backDataDirectory))
                System.IO.Directory.CreateDirectory(backDataDirectory);
        }

        public void Save()
        {
            if (File.Exists(currentDataFilePath))
            {
                //MoveToBackup();
                File.Delete(currentDataFilePath);
            }
            Save(currentDataFilePath);
        }

        public void Save(String path)
        {
            var fstream = System.IO.File.Create(path);
            using (var binaryWriter=new BinaryWriter(fstream))
            {
                //保存镜像
                SaveDir(rootDir,binaryWriter);
            }
        }

        /// <summary>
        /// 保存目录
        /// </summary>
        /// <param name="dirInfo"></param>
        /// <param name="binaryWriter"></param>
        public void SaveDir(NodeBase dirInfo, BinaryWriter binaryWriter)
        {
            if(!dirInfo.IsDirectory())
                return;
            binaryWriter.Write(1);
            var dir = (DirectoryNodeInfo)dirInfo;
            var length = dir.Childs.Count;
            dir.WriteToBinary(binaryWriter);
            binaryWriter.Write(length);
            foreach (var nodeBase in dir.Childs)
            {
                if (!nodeBase.IsDirectory())
                {
                    binaryWriter.Write(0);
                    var file = (FileNodeInfo) nodeBase;
                    file.WriteToBinary(binaryWriter);
                    continue;
                }
                SaveDir(nodeBase, binaryWriter);
            }
        }

        public void MoveToBackup()
        {
            System.IO.File.Move(currentDataFilePath, backDataDirectory + "/fsImage_" + DateTime.Now.ToString("yyyy-MM-dd"));
        }

        /// <summary>
        /// 读取一个目录
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="binaryReader"></param>
        public void ReadDir(NodeBase parent, BinaryReader binaryReader)
        {
            if(parent==null||!parent.IsDirectory()) return;
            var dir = new IO.Directory(parent);
            
            var length = binaryReader.ReadInt32();
            for (int i = 0; i < length; i++)
            {
                var type = binaryReader.ReadInt32();
                NodeBase nodeBase=null;
                if (type == 1)
                {
                    //Dir
                    nodeBase=new DirectoryNodeInfo();
                    nodeBase.ReadFromBinary(binaryReader);
                    ReadDir(nodeBase, binaryReader);
                }
                else if(type==0)
                {
                    //File
                    nodeBase=new FileNodeInfo();
                    nodeBase.ReadFromBinary(binaryReader);
                    foreach (var fileBlockInfo in ((FileNodeInfo)nodeBase).Blocks)
                    {
                        nameNode.BlockManager.GetBlockMap().AddBlockInfo(fileBlockInfo);
                    }
                }
                dir.AddChildren(nodeBase);
            }
        }

        public DirectoryNodeInfo GetFileSystem()
        {
            var root = new DirectoryNodeInfo("", "", DateTime.Now.LongNow(), "Root", null);
            if (File.Exists(currentDataFilePath))
            {
                var fstream = File.Open(currentDataFilePath, FileMode.Open);
                using (var binaryReader=new BinaryReader(fstream))
                {
                    //读取镜像
                    var type = binaryReader.ReadInt32(); //useless data
                    root.ReadFromBinary(binaryReader);
                    ReadDir(root, binaryReader);
                }
            }
            rootDir = root;
            return root;
        }
    }
}